#include <iterator>
#include "MarkupSTL.h"
#include "global.h"
#include "Game.h"
#include "RedisClient.h"
#include "Logic.h"
#include "json.h"
#include "util.h"
#include "globalExtern.h"
#include "Host.h"
#include "CClient.h"
#include "NodeServer.h"
#include <atomic>
#include <thread>
#include "log.h"
#include <functional>
#include "def.h"
#include "HttpDecoder.h"


using namespace std::placeholders;

CGameServer::CGameServer()
{
}

CGameServer::~CGameServer()
{
}

bool CGameServer::InitGame()
{	
	if (0 != m_http_server.Start("0.0.0.0", TGlobal::_param1, std::bind(&CGameServer::ProcHttp, this, _1, _2)))
	{
		log_error("http server start failed,port:%d", TGlobal::_param1);
		return false;
	}

	if (!m_curl_client.Initialize())
	{
		log_error("curl client initialize failed");
		return false;
	}
	
	// StartTimerMillisecond(10010, 1, true);
	return true;
}

static std::int64_t total_send_cnt = 0;
static std::int64_t total_cost_cnt = 0;
static std::int64_t total_success_cnt = 0;
static std::int64_t total_cost_us = 0;
static std::int64_t g_pre = 0;
static std::int64_t g_cur = 0;
static std::int64_t g_send_qps = 0;
static std::int64_t g_recv_qps = 0;
static std::string g_test_url;
static std::vector<std::int64_t> g_cur_times;
static std::vector<std::int64_t> g_pre_sec;
static int g_max_times = 0;
CurlProxy* m_curl_proxy = NULL;
std::queue<std::int32_t> g_index_queue;
static bool g_handler_timer = false;
	
int CGameServer::OnBYTimeOut(int Timerid)
{
	switch (Timerid)
	{
	case 10010:
	{
		for (int i = 0; i < 1000; i++)
		{
			if (g_index_queue.empty()) break;
			int index = g_index_queue.front();
			PostMessage(g_test_url, index, g_cur_times[index], g_max_times);
			g_index_queue.pop();
		}			
		if (g_index_queue.size())
		{
			StartTimerMillisecond(10010, 0, false);
		}
		else
		{
			g_handler_timer = false;
		}
	}
		break;
	
	default:
		break;
	}
	return 0;
}

int CGameServer::ProcessPacket(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	log_debug("cmd=0x%x,  ", inputPkg->GetCmdType());


	
	return 0;
}

int CGameServer::ProcEventBackConn(int ev_id, SpiderEvent* pEvent)
{
	return 0;
}

void CGameServer::PostMessage(const std::string& url, int index, int times, int max_times)
{
	std::uint64_t now = CTools::GetUnixTimeMs();
	static std::uint64_t transid = now;
	total_send_cnt++;

	stHttpRequest curl_req;
	curl_req.url = url;  // 调整请求路径
	curl_req.body = std::to_string(index);
	curl_req.heads = {{"Connection","close"}};
	curl_req.method = "POST";
	
	g_cur_times[index]++;
	g_pre_sec[index] = now;

	++transid;
	
	m_curl_client.RequestAsync(transid, std::move(curl_req));
	// m_curl_proxy->RequestAsync(transid, std::move(curl_req));
	g_cur = now / 1000000;
	g_send_qps++;
	if (g_cur != g_pre) 
	{
		log_info("g_send_qps:%lld,g_recv_qps:%lld,cost:%lld,success:%lld,times:%lld", g_send_qps, g_recv_qps, g_cur - g_pre, total_success_cnt, total_cost_cnt);
		g_pre = g_cur;
		g_send_qps = 1;
		g_recv_qps = 0;
	}
}
void CGameServer::OnPostResponse(std::uint64_t transid, int err, stHttpResponse&& response)
{
	total_cost_cnt++;

	std::string url = "";
	int index = strtol(response.body.c_str(), NULL, 10);
	int times = g_cur_times[index];
	int max_times = g_max_times;
	std::uint64_t pre_now = g_pre_sec[index];

	std::uint64_t now = CTools::GetUnixTimeMs();
	std::uint64_t deta = now - pre_now;
	total_cost_us += deta;

	if (err == 0)
	{
		total_success_cnt++;
	}

	g_cur = now / 1000000;
	g_recv_qps++;
	if (g_cur != g_pre) 
	{
		log_info("g_send_qps:%lld,g_recv_qps:%lld,cost:%lld,success:%lld,times:%lld", g_send_qps, g_recv_qps, g_cur - g_pre, total_success_cnt, total_cost_cnt);
		g_pre = g_cur;
		g_send_qps = 0;
		g_recv_qps = 1;
	}

	if (err != 0)
	{
		log_debug("index:%d,times:%d is err:%d,response:%s", index, times, err, response.ToString().c_str());
		return ;
	}

	if (times >= max_times)
	{
		log_debug("index:%d,times:%d,max_times:%d,response:%s", index, times, max_times, response.ToString().c_str());
		log_info("send:%lld,recv:%lld,success:%lld,avg:%f", total_send_cnt, total_cost_cnt, total_success_cnt, (1.0*total_cost_us/total_cost_cnt));
		return ;
	}

	g_index_queue.emplace(index);

	if (!g_handler_timer)
	{
		g_handler_timer = true;
		StartTimerMillisecond(10010, 0, false);
	}
	// PostMessage(g_test_url, index, times, max_times);
}

int CGameServer::ProcHttp(std::uint32_t request_id, stHttpRequest&& http_req)
{
	stUrlData st_url_data;
	if (!HttpDecoder::ParserUrl(st_url_data, http_req.url))
	{
		// 无效url
		return -1;
	}
	log_debug("id:%u,req:%s", request_id, http_req.ToString().c_str());
	// 根据路径处理
	if (MatchUrlMethod("/pingpong", st_url_data.path.c_str(), st_url_data.path.size()))
	{
		static std::int64_t pp_pre = 0;
		static std::int64_t pp_send_qps = 0;
		static std::int64_t pp_recv_qps = 0;

		std::uint64_t recv_us = CTools::GetUnixTimeMs();
		// 测试,发什么回什么
		stHttpResponse http_resp;
		http_resp.state = 200;
		http_resp.heads = std::move(http_req.heads);
		http_resp.body = std::move(http_req.body);
		ResponseHttp(request_id, std::move(http_resp));
		std::uint64_t send_us = CTools::GetUnixTimeMs();
		std::uint64_t deta = send_us - recv_us;
		if (deta > 50000)
		{
			log_info("cost %lld", deta);
		}

		std::int64_t pp_cur_recv = recv_us / 1000000;
		std::int64_t pp_cur_send = send_us / 1000000;
		pp_recv_qps++;
		pp_send_qps++;
		if (pp_cur_send != pp_pre) 
		{
			log_info("send_qps:%lld,recv_qps:%lld,cost:%lld", pp_send_qps, pp_recv_qps, pp_cur_send - pp_pre);
			pp_pre = pp_cur_send;
			pp_send_qps = 1;
			pp_recv_qps = 1;
		}
	}
	else if (MatchUrlMethod("/curl/test/pingpong", st_url_data.path.c_str(), st_url_data.path.size()))
	{
		total_cost_cnt = 0;
		total_success_cnt = 0;
		total_cost_us = 0;

		int num = strtol(http_req.heads["num"].c_str(), NULL, 10);
		int times = strtol(http_req.heads["times"].c_str(), NULL, 10);
		std::string target_url = http_req.body;
		if (num < 1) num = 1;
		if (times < 1) times = 1;
		stHttpResponse http_resp;
		http_resp.state = target_url.empty()?404:200;
		ResponseHttp(request_id, std::move(http_resp));
		
		if (http_resp.state != 200)
		{
			return -1;
		}

		// do task test
		g_cur_times.clear();
		g_cur_times.resize(num, 0);
		g_pre_sec.resize(num, 0);
		if (g_test_url.empty()) g_test_url = target_url;
		if (0 == g_max_times) g_max_times = times;

		if (m_curl_proxy == NULL)
		{
			m_curl_proxy = new CurlProxy(target_url, true);
			m_curl_proxy->Initialize();
			m_curl_proxy->SetResponseCb(std::move(std::bind(&CGameServer::OnPostResponse, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
		}

		m_curl_client.SetResponseCb(std::move(std::bind(&CGameServer::OnPostResponse, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));

		for (int i=0; i < num; i++)
		{
			g_index_queue.emplace(i);
		}
		if (!g_handler_timer)
		{
			g_handler_timer = true;
			StartTimerMillisecond(10010, 0, false);
		}
	}
	else if (MatchUrlMethod("/curl/test", st_url_data.path.c_str(), st_url_data.path.size()))
	{
		// 发什么回什么
		stHttpResponse http_resp;
		http_resp.state = 200;
		http_resp.body = http_req.body;
		ResponseHttp(request_id, std::move(http_resp));
	}
	else if (MatchUrlMethod("/curl/async", st_url_data.path.c_str(), st_url_data.path.size()))
	{
		stHttpRequest curl_req(http_req);
		// curl_req.url = "http://127.0.0.1:5162/curl/test";  // 调整请求路径
		curl_req.url = "http://127.0.0.1:5015/curl/test";  // 调整请求路径
		log_debug(" req:%s", curl_req.ToString().c_str());

		auto cb = [request_id, this](std::uint64_t transid, int err, stHttpResponse&& response)
		{
			// 发什么回什么
			this->ResponseHttp(request_id, std::move(response));
		};
		std::uint64_t transid = time(NULL);
		m_curl_client.SetResponseCb(std::move(cb));
		int rc = m_curl_client.RequestAsync(transid, std::move(curl_req));
		if (rc != 0)
		{
			stHttpResponse http_resp;
			http_resp.state = 403;
			http_resp.body = "failed:"+std::to_string(rc);
			ResponseHttp(request_id, std::move(http_resp));
		}
	}
	else if (MatchUrlMethod("/curl", st_url_data.path.c_str(), st_url_data.path.size()))
	{
		stHttpRequest curl_req(http_req);
		curl_req.url = "http://127.0.0.1:5162/curl/test";  // 调整请求路径
		// curl_req.url += "/test";  // 调整请求路径
		log_debug(" req:%s", curl_req.ToString().c_str());

		stHttpResponse http_resp;
		int rc = m_curl_client.Request(std::move(curl_req), http_resp);
		log_debug("rc:%d", rc);
		if (rc != 0)
		{
			http_resp.body = "failed:"+std::to_string(rc);
			ResponseHttp(request_id, std::move(http_resp));
		}
		else 
		{
			ResponseHttp(request_id, std::move(http_resp));
		}
	}
	else 
	{
		// 默认返回ok
		stHttpResponse http_resp;
		http_resp.state = 200;
		http_resp.body = "ok";
		ResponseHttp(request_id, std::move(http_resp));
	}
	
	return 0;
}

int CGameServer::ResponseHttp(std::uint32_t request_id, stHttpResponse&& http_resp)
{
	log_debug("id:%u,resp:%s", request_id, http_resp.ToString().c_str());
	return m_http_server.Response(request_id, std::move(http_resp));
}





